;*****************************************************************************************************
;+
; NAME:
;       IGL_MOVETOOL
;
; PURPOSE:
;
;       This is a CATTOOL object representing a move operation in a
;       IGL_Window. It is written to be able to undo/redo the move.
;
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
; SUPERCLASSES:
;
;       CATTOOL (Catalyst Library)
;
; SYNTAX:
;
;       tool = Obj_New('IGL_MoveTool')
;
;
; CLASS_STRUCTURE:
;
;       class = {IGL_MoveTool, $      
;                INHERITS CATTOOL $   ; Inherits the CATTOOL object class.
;               }
;
;
; MODIFICATION_HISTORY:
;
;       Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::APPLY
;
; PURPOSE:
;
;       This method apply the move operation. It saves the
;       target's current position and sets it to the previously
;       stored position.
;
; SYNTAX:
;
;       self -> Apply
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       DRAW:   Set this keyword to call the draw method of the target
;               object after the tool is applied.
;
;-
;*****************************************************************************************************
PRO IGL_MoveTool::Apply, Draw=draw

   @cat_pro_error_handler

   ;; Make sure there is available cached data
   IF PTR_VALID(self._theCache) EQ 0 THEN RETURN
   
   ;; Make sure there is a valid target object.
   IF (OBJ_ISA_VALID(self._theTarget,'CATDATAATOM') EQ 0) THEN return
   
   self -> GetProperty, cached_data=OldPosition
  
   CASE strupcase(obj_class(self._theTarget)) OF
      
      'IGL_GRAPHIC': BEGIN
         self._theTarget -> GetProperty, coord_object=coords
         IF (obj_isa_valid(coords,'CatCoord')) THEN BEGIN
            coords -> GetProperty, position=currentPosition
            self -> Cache, currentPosition
         ENDIF
         self._theTarget -> SetProperty, position=OldPosition
      END
      
      'IGL_TEXT': BEGIN
         self._theTarget -> GetProperty, x=x, y=y
         self._theTarget -> SetProperty, x=OldPosition[0], y=OldPosition[1]
         self -> Cache, [x,y]
      END

      'IGL_COLORBAR': BEGIN
         self._theTarget -> GetProperty, position=currentPosition
         self._theTarget -> SetProperty, position=OldPosition
         self -> Cache, currentPosition
      END

      'IGL_POLYGON': BEGIN
         self._theTarget -> GetProperty, xpts=xpts, ypts=ypts
         self._theTarget -> SetProperty, xpts=OldPosition[*,0], ypts=OldPosition[*,1]
         self -> Cache, [[xpts],[ypts]]
      END

      'IGL_IMAGE': BEGIN
         self._theTarget -> GetProperty, position=position
         self._theTarget -> SetProperty, position=Oldposition
         self -> Cache, position
      END

      'IGL_LEGEND': BEGIN
         self._theTarget -> GetProperty, XPOS=xpos, YPOS=ypos
         self._theTarget -> SetProperty, XPOS=OldPosition[0], YPOS=OldPosition[1]
         self -> Cache, [xpos,ypos]
      END
            
   ENDCASE

   ; Need a draw method?
   IF Keyword_Set(draw) THEN self._theTarget -> Draw

   ;; Report completion
   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::CACHEPOSITION
;
; PURPOSE:
;
;       This method stores the current position of the target object
;       into the cache.
;
; SYNTAX:
;
;       self -> CachePosition
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       None.
;
;-
;*****************************************************************************************************
PRO IGL_MoveTool::CachePosition

  @cat_pro_error_handler

  ;; Cache the relevant position information for the target object
  ;; depending on its class
  IF (obj_isa_valid(self._theTarget,'CATDATAATOM') EQ 0) THEN return
  
  CASE strupcase(obj_class(self._theTarget)) OF

     'IGL_GRAPHIC': BEGIN
        self._theTarget -> GetProperty, coord_object=coords
        IF (obj_isa_valid(coords,'CatCoord')) THEN BEGIN
           coords -> GetProperty, position=position
           self -> Cache, position
        ENDIF        
     END

     'IGL_TEXT': BEGIN
        self._theTarget -> GetProperty, x=x, y=y
        self -> Cache, [x,y]
     END

     'IGL_COLORBAR': BEGIN
        self._theTarget -> GetProperty, position=position
        self -> Cache, position
     END

     'IGL_POLYGON': BEGIN
        self._theTarget -> GetProperty, xpts=xpts, ypts=ypts
        self -> Cache, [[xpts],[ypts]]
     END

     'IGL_IMAGE': BEGIN
        self._theTarget -> GetProperty, position=position
        self -> Cache, position
     END

     'IGL_LEGEND': BEGIN
        self._theTarget -> GetProperty, XPOS=xpos, YPOS=ypos
        self -> Cache, [xpos,ypos]
     END

     ELSE:

  ENDCASE

  ;; Report completion
  self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::COMPARECACHEDATA
;
; PURPOSE:
;
;       This method compares the current position of the target object
;       to the one stored in the cache. It returns 1 if they are
;       different and 0 if they are equal.
;
; SYNTAX:
;
;       HasChanged = self -> CompareCacheData()
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       None.
;
;-
;*****************************************************************************************************
FUNCTION IGL_MoveTool::CompareCacheData

  @cat_func_error_handler

  ;; Make sure we have a position stored in the cache
  IF Ptr_Valid(self._theCache) EQ 0 THEN RETURN, 0

  ;; Make sure we have a valid target object
  IF (obj_isa_valid(self._theTarget,'CATDATAATOM') EQ 0) THEN return, status 

  ;; Get the data in the cache
  self -> GetProperty, cached_data=OldPosition

  ;; Compare the current position to the old one. The "position" of
  ;; the target object depends on which class it is.
  CASE strupcase(obj_class(self._theTarget)) OF

     'IGL_GRAPHIC': BEGIN
        self._theTarget -> GetProperty, coord_object=coords
        IF (obj_isa_valid(coords,'CatCoord')) THEN BEGIN
           coords -> GetProperty, position=position
           IF (ARRAY_EQUAL(position,OldPosition) EQ 0) THEN RETURN, 1
        ENDIF        
     END

     'IGL_TEXT': BEGIN
        self._theTarget -> GetProperty, x=x, y=y
        IF ((X NE OldPosition[0]) OR (Y NE OldPosition[1])) THEN RETURN, 1
     END

     'IGL_COLORBAR': BEGIN
        self._theTarget -> GetProperty, position=position
        IF (ARRAY_EQUAL(position,OldPosition) EQ 0) THEN RETURN, 1
     END

     'IGL_POLYGON': BEGIN
        self._theTarget -> GetProperty, xpts=xpts, ypts=ypts
        IF (ARRAY_EQUAL(xpts,OldPosition[*,0]) EQ 0) THEN RETURN, 1
        IF (ARRAY_EQUAL(ypts,OldPosition[*,1]) EQ 0) THEN RETURN, 1
     END

     'IGL_LEGEND': BEGIN
        self._theTarget -> GetProperty, XPOS=xpos, YPOS=ypos
        IF (ARRAY_EQUAL([xpos,ypos],OldPosition) EQ 0) THEN RETURN, 1
     END

     'IGL_IMAGE': BEGIN
        self._theTarget -> GetProperty,  position=pos
        IF (ARRAY_EQUAL(pos,OldPosition) EQ 0) THEN RETURN, 1
     END

     ELSE:

  ENDCASE

  ;; Report completion
  self -> Report, /Completed

  RETURN, 0

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::GETPROPERTY
;
; PURPOSE:
;
;       This method is used to get the object's properties.
;
; SYNTAX:
;
;       self -> GetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     _REF_EXTRA:     Any keywords appropriate for the superclass GetProperty method.
;-
;*****************************************************************************************************
PRO IGL_MoveTool::GetProperty, _REF_EXTRA=extraKeywords

   @cat_pro_error_handler

   IF (N_ELEMENTS (extraKeywords) GT 0) THEN self -> CATTOOL::GetProperty, _EXTRA=extraKeywords

   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::REDO
;
; PURPOSE:
;
;       This method redo the move operation on the target object.
;
; SYNTAX:
;
;       self -> Redo
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       DRAW:    Set this keyword to call the draw method of the
;                target object after the tool is applied.
;
;-
;*****************************************************************************************************
PRO IGL_MoveTool::Redo, Draw=draw

   @cat_pro_error_handler
   
   self -> Apply, Draw=draw

   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::SETPROPERTY
;
; PURPOSE:
;
;       This method is used to set the object's properties.
;
; SYNTAX:
;
;       self -> SetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     _EXTRA:       Any keyword accepted by the SetProperty method of
;                   the CATTOOL superclass.
;-
;*****************************************************************************************************
PRO IGL_MoveTool::SetProperty, _EXTRA=extraKeywords

   @cat_pro_error_handler

   IF (N_ELEMENTS (extraKeywords) GT 0) THEN self -> CATTOOL::SetProperty, _EXTRA=extraKeywords

   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::UNDO
;
; PURPOSE:
;
;       This method undo the move operation on the target object.
;
; SYNTAX:
;
;       self -> Undo
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       DRAW:    Set this keyword to call the draw method of the
;                target object after the tool is applied.
;
;-
;*****************************************************************************************************
PRO IGL_MoveTool::Undo, DRAW=draw

   @cat_pro_error_handler
   
   self -> Apply, draw=draw
   
   IF (obj_valid(self)) THEN self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::CLEANUP
;
; PURPOSE:
;
;       This is the IGL_MoveTool object class destructor method.
;
; SYNTAX:
;
;       Called automatically when the object is destroyed.
;
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     None.
;-
;*****************************************************************************************************
PRO IGL_MoveTool::CLEANUP

   @cat_pro_error_handler

   self -> CATTOOL::CLEANUP

   self -> Report, /Completed
   
END

;*****************************************************************************************************
;+
; NAME:
;       IGL_MoveTool::INIT
;
; PURPOSE:
;
;       This is the IGL_MoveTool object class creator method.
;
; SYNTAX:
;
;       Called automatically when the object is created.
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     _EXTRA:       Any keywords accepted by the CATTOOL::Init method.
;
;-
;*****************************************************************************************************
FUNCTION IGL_MoveTool::INIT, _Extra=extraKeywords

   @cat_func_error_handler

   ; Call superclass INIT method
   ok = self -> CATTOOL::Init(_Extra=extraKeywords)

   IF (NOT ok) THEN RETURN, 0

   self -> Report, /completed
   
   RETURN, 1

END

;*****************************************************************************************************
;
; NAME:
;       IGL_MOVETOOL CLASS DEFINITION
;
; PURPOSE:
;
;       This is the IGL_MoveTool object's structure definition code.
;
;*****************************************************************************************************
PRO IGL_MoveTool__DEFINE, class

  COMPILE_OPT idl2, HIDDEN

  class = {IGL_MoveTool, $      
           INHERITS CATTOOL $   ; Inherits the CATTOOL object class.
          }

  struct_hide, class

END
